home *** CD-ROM | disk | FTP | other *** search
/ Crack It! / Crack It!.iso / CONTENT / DISKEDIT / DISKEDIT.PAS < prev    next >
Pascal/Delphi Source File  |  1996-09-13  |  36KB  |  1,223 lines

  1. {
  2.  ***
  3.  
  4.  DISKEDIT
  5.  Disk View/Edit Utility Version 3.00
  6.  (C)Copyright Gerard Paul Java 1996
  7.  
  8.  Program Source File
  9.  
  10.  
  11.  This program allows viewing and editing of individual logical disk sectors.
  12.  It deals with logical DOS drives, rather than the physical drives in the
  13.  computer.
  14.  
  15.  This allows unrestricted access and modification to any DOS disk's sector.
  16.  Therefore, extreme caution must be exercised when modifying any sector,
  17.  especially if it is the system area (boot, FAT, root directory).
  18.  
  19.  This program is intended only for IBM PCs, XTs, ATs, PS/2s, and their 100%
  20.  compatible computers, running on DOS version 2.10 or later.  No provisions
  21.  for porting over to other computers, operating systems, or Pascal compilers
  22.  exist.  The program will most likely not run on systems other than those
  23.  mentioned above.
  24.  
  25.  Do not use this program on any multitasking operating environment such
  26.  as Windows.  The disk access is absolute, and the operating system
  27.  may be disrupted by this.  This program will either not function properly
  28.  or may cause corrupted data.  Use only under single-tasking DOS mode
  29.  if necessary.
  30.  
  31.  This program is free software; you may distribute and/or modify it under
  32.  the terms of the GNU General Public License version 2 or (at your option)
  33.  any later version, as published by the Free Software Foundation.
  34.  
  35.  This program is distributed in the hope that it will be useful, but is
  36.  provided "AS IS", WITHOUT ANY WARRANTY, either expressed or implied,
  37.  including, but not limited to, warranty of MERCHANTABILITY or FITNESS FOR
  38.  A PARTICULAR PURPOSE.  See the GNU General Public License for details.
  39.  
  40.  You should have received a copy of the GNU General Public License along
  41.  with this program; if not, write to the Free Software Foundation, Inc.,
  42.  675 Mass Ave., Cambridge, MA 02139 USA.
  43.  
  44.  REVISION HISTORY:
  45.  
  46.    Version 3.00 - 5/23/94       Blue/white color scheme
  47.  
  48.  ***
  49. }
  50.  
  51. {$A+,B-,F-,I-,R-,S-,V-}
  52. {$M 3072,0,10752}
  53.  
  54. program DiskEdit;
  55. uses
  56.  Dos,
  57.  Crt,
  58.  ScreenRt,
  59.  AbsDisk,
  60.  HexFuncs,
  61.  SysRt,
  62.  Instruc,
  63.  Error,
  64.  IntroRt,
  65.  MenuRt;
  66.  
  67. const
  68.   Selected = True;
  69.   NotSelected = False;
  70.  
  71.   ErrInst1 = 'Press R to retry or Esc to cancel';
  72.  
  73.   RetryOrCancel = 'R'+Esc;
  74.  
  75. type
  76.   Parameter1Type = string[2];
  77.  
  78.   HexByte = string[2];
  79.   KeysString = string[3];
  80.  
  81.   ParaType = array[0..15] of byte;
  82.  
  83.   DataListType = ^ParaRecord;
  84.   ParaRecord = record
  85.          Paragraph: ParaType;
  86.          Next,Prev: DataListType;
  87.            end;
  88.  
  89.   PtrRecord = record
  90.                 Offset: word;
  91.                 Segment: word;
  92.               end;
  93.  
  94.   DiskObjType = object
  95.                   List: DataListType;
  96.                   SectorSize: word;
  97.                   NumSectors: longint;
  98.           Drive: byte;
  99.           LargePartition: boolean;
  100.                   BtoA: boolean;
  101.                   procedure SetDrive(var Signal: boolean);
  102.                   procedure Operate;
  103.                 end;
  104.  
  105. var
  106.   Parameter1: Parameter1Type;
  107.   Regs: Registers;
  108.  
  109.   BackScreenBuff: ScreenBufferType;
  110.   MenuScreenBuff: ScreenBufferType;
  111.   AuxScreenBuffer: ScreenBufferType;
  112.  
  113.   SectorList: DiskObjType;
  114.  
  115.   Menu: MenuType;
  116.  
  117.  
  118. {---------------------------------------------------------------------------
  119.  InitValues: Sets the color attributes depending on the screen mode and the
  120.  BW environment variable.
  121.  ---------------------------------------------------------------------------}
  122.  
  123. procedure InitValues;
  124. begin
  125.   if (LastMode = Mono) or (GetEnv('BW') = '1') then
  126.     begin
  127.       NormOptKeyAttr := $7F;
  128.       SelectedOptKeyAttr := $F;
  129.       OptionNormTextAttr := $70;
  130.       OptionSelectedTextAttr := $7;
  131.       BoxAttr := $7F;
  132.       TextNormAttr := $70;
  133.       HelpLineTextAttr := $F;
  134.       ErrBoxAttr := $F;
  135.       ErrMsgAttr := $F;
  136.       TextHighAttr := $7F;
  137.     end
  138.   else
  139.     begin
  140.       TextNormAttr := $1E;
  141.       BoxAttr := $13;
  142.       TextHighAttr := $1B;
  143.       NormOptKeyAttr := $1B;
  144.       SelectedOptKeyAttr := $B;
  145.       OptionNormTextAttr := $1E;
  146.       OptionSelectedTextAttr := $E;
  147.       HelpLineTextAttr := $71;
  148.       ErrBoxAttr := $4F;
  149.       ErrMsgAttr := $4E;
  150.     end;
  151.  
  152.     SetTSSRValues;
  153. end;
  154.  
  155. {---------------------------------------------------------------------------
  156.  ShowHelpScreen: The DISKEDIT help system.
  157.  ---------------------------------------------------------------------------}
  158.  
  159. procedure ShowHelpScreen(ScreenNo: byte);
  160. begin { proc }
  161.   Window(1,1,80,25);
  162.   SaveScreen(AuxScreenBuffer);                  { Save screen. }
  163.   JustSeeBox;
  164.   TextAttr := BoxAttr;
  165.  
  166.   case ScreenNo of
  167.     0: begin
  168.          DrawBox(3,3,78,23,DoubleLine);
  169.          GotoXY(31,3);Write(' Help: Help System ');
  170.          Window(5,5,78,25);TextAttr := TextNormAttr;
  171.  
  172.          Writeln('At almost any point in this program, press F1 for help (help is not');
  173.          Writeln('available at error and instruction boxes).  Each help screen contains');
  174.          Writeln('instructions on what to do at the point from where it was invoked.');
  175.          Writeln;
  176.          Writeln('The bottom line of the sector view/edit screen contains a list of the');
  177.          Writeln('function keys available, and their corresponding functions.  The help');
  178.          Writeln('screen contains more detailed instructions.');
  179.          Writeln;
  180.          Writeln('This program can modify any disk sector.  So BE VERY CAREFUL WHEN');
  181.          Writeln('CHANGING THE DISK DATA!  CORRUPTED DATA IN ANY OF THE RESERVED SECTORS');
  182.          Writeln('(boot sector, FATs, root directory) COULD MAKE PART OR ALL OF THE DISK');
  183.          Writeln('INACCESSIBLE, AND IMPROPER MODIFICATION OF THE DATA AREA CAN CORRUPT');
  184.          Writeln('DATA IN THE FILES.');
  185.          Writeln;
  186.          Writeln('See the manual for details.');
  187.          Writeln;
  188.        end;  { 0 }
  189.     1: begin
  190.          DrawBox(3,6,78,19,DoubleLine);
  191.          GotoXY(30,6);Write(' Help: Menu Operation ');
  192.          Window(5,8,78,20);TextAttr := TextNormAttr;
  193.  
  194.          Writeln('The Up and Down cursor keys move the selection bar up and down respect-');
  195.          Writeln('ively.  Home and End move it to the first and last options respectively.');
  196.          Writeln('Enter executes the option indicated by the bar.');
  197.          Writeln;
  198.          Writeln('Pressing the highlighted letters directly executes their corresponding');
  199.          Writeln('options.');
  200.          Writeln;
  201.          Writeln('The bottom line of the screen shows a description of the function of the');
  202.          Writeln('option indicated by the selection bar.');
  203.        end; { 1 }
  204.     2: begin
  205.          GotoXY(24,25);ClrEol;
  206.          DrawBox(3,3,78,23,DoubleLine);
  207.          GotoXY(29,3);Write(' Help: View/Edit Screen');
  208.          Window(5,5,78,24);TextAttr := TextNormAttr;
  209.  
  210.          Writeln('Use the cursor keys to move the cursor around the data dump.  Use the');
  211.          Writeln('PgUp and PgDn keys to read the previous and next sectors respectively.');
  212.          Writeln('Use Home and End to read the first and last disk sectors respectively.');
  213.          Writeln('Press F5 to view a specific sector.');
  214.          Writeln;
  215.          Writeln('To edit a sector, use the F2 key to select the edit mode (hex or ASCII)');
  216.          Writeln('and enter the new data.  Enter hexadecimal numbers in hex mode, type in');
  217.          Writeln('the new data in ASCII mode.  (In hex mode, the Backspace key moves the');
  218.          Writeln('cursor back one character if the first digit has already been changed.');
  219.          Writeln('In ASCII mode, it enters an ASCII 8 character.)  Press F4 to write the');
  220.          Writeln('changes to disk, or F3 to discard them.');
  221.          Writeln;
  222.          Writeln('The edit mode is indicated by the location of the blinking cursor.  In');
  223.          Writeln('hex mode, it is positioned on the hex dump.  In ASCII mode, it is on the');
  224.          Writeln('ASCII dump.');
  225.          Writeln;
  226.        end;
  227.   end;
  228.   Writeln;
  229.   TextAttr := TextHighAttr;Write(ContMsg);         { Display message. }
  230.   WaitForKeypress;
  231.   RestoreScreen(AuxScreenBuffer);                  { Get rid of help. }
  232. end; { proc }
  233.  
  234.  
  235. {---------------------------------------------------------------------------
  236.  CommandHelp: Displays information on the DISKEDIT command.
  237.  ---------------------------------------------------------------------------}
  238.  
  239. procedure CommandHelp;
  240. begin
  241.   Writeln;
  242.   Writeln('Help on the DISKEDIT command:');
  243.   Writeln;
  244.   Writeln('Command syntax: DISKEDIT [/?]');
  245.   Writeln;
  246.   Writeln('The command takes no parameters other than /?, which brings up this screen.');
  247.   Writeln('Set the CGASNOWCHECK environment variable to 1 (with a SET CGASNOWCHECK=1');
  248.   Writeln('command from the DOS prompt) to suppress "snow" on old CGAs.  Likewise set');
  249.   Writeln('BW environment variable to 1 to bring the program up in black-and-white mode.');
  250.   Writeln;
  251.   Writeln;
  252.   Writeln('DISKEDIT Version 3.00: (C)Copyright Gerard Paul Java 1996');
  253. end;
  254.  
  255.  
  256. {---------------------------------------------------------------------------
  257.  IndicateError: Displays an error box and waits for the response.
  258.  ---------------------------------------------------------------------------}
  259.  
  260. procedure IndicateError(Msg1,Msg2: ErrStrType;ValidKeys: KeysString;
  261.                         var Keystroke: char);
  262. begin
  263.   SaveScreen(AuxScreenBuffer);
  264.  
  265.   Window(1,25,80,25);TextAttr := TextNormAttr;
  266.   ClrEol;
  267.   ErrBox(Msg1,Msg2,Instruct);
  268.  
  269.   repeat
  270.     Keystroke := Upcase(GetKeyNoExt);
  271.   until Pos(Keystroke,ValidKeys) <> 0;
  272.  
  273.   RestoreScreen(AuxScreenBuffer);
  274. end;
  275.  
  276.  
  277. procedure MemError;
  278. type
  279.   MemValStr = string[4];
  280.  
  281. var
  282.   ShortMem: MemValStr;
  283.  
  284. begin
  285.   SaveScreen(AuxScreenBuffer);
  286.   Str(10240-MemAvail,ShortMem);
  287.   ErrBox('Error: not enough memory (short by '+ShortMem+' bytes)',
  288.          'Press a key to return to menu',Instruct);
  289.   WaitForKeypress;
  290.   RestoreScreen(AuxScreenBuffer);
  291. end;
  292.  
  293.  
  294. {---------------------------------------------------------------------------
  295.  SetDrive: Sets the drive whose disk will be accessed, and the proper
  296.  parameters the program will use to properly access the disk.
  297.  ---------------------------------------------------------------------------}
  298.  
  299. procedure DiskObjType.SetDrive(var Signal: boolean);
  300. type
  301.   DriveStr = string[1];
  302.  
  303. var
  304.   BootPtr: pointer;
  305.   EnteredDrive: DriveStr;
  306.   Keystroke: char;
  307.   Result: word;
  308.   OldDrive: byte;
  309.   ReservedSectors: word;
  310.  
  311.   DumFile: file;
  312.   IOCode: longint;
  313.  
  314. begin
  315.   TextAttr := BoxAttr;
  316.  
  317.   Window(1,1,80,25);
  318.   DrawBox(32,11,49,13,DoubleLine);
  319.   TextAttr := TextNormAttr;
  320.   GotoXY(2,25);Write('Enter a drive letter');ClrEol;
  321.   GotoXY(34,12);Write('Enter drive: ');
  322.  
  323.   TextAttr := $F;
  324.   Write(' ');
  325.  
  326.   GotoXY(47,12);GetInput(EnteredDrive,1,Signal);
  327.  
  328.   RestoreScreen(BackScreenBuff);
  329.  
  330.  
  331.   { Equate drive B to A on single-floppy systems }
  332.  
  333.   if ((BIOSEquipList and $00C0) = 0) and (EnteredDrive = 'B') then
  334.     begin
  335.       EnteredDrive := 'A';
  336.       BtoA := True;
  337.     end
  338.   else
  339.     BtoA := False;
  340.  
  341.   if not Signal then
  342.     begin
  343.       if EnteredDrive <> '' then
  344.         begin
  345.           Assign(DumFile,EnteredDrive+':\NUL');    { Check if drive valid. }
  346.           Reset(DumFile);                { Error if drive not found. }
  347.          end;
  348.  
  349.       IOCode := IOResult;
  350.  
  351.       if (IOCode = 3) or (EnteredDrive = '') then
  352.         begin
  353.           SaveScreen(AuxScreenBuffer);
  354.  
  355.           ErrBox('Error: invalid drive entered','Press a key to return to menu',Instruct);
  356.           WaitForKeypress;
  357.           RestoreScreen(AuxScreenBuffer);
  358.           Signal := True;
  359.         end
  360.       else
  361.         begin
  362.           if IOCode = 0 then
  363.             Close(DumFile);                      { Release handle. }
  364.  
  365.           repeat
  366.             Drive := Ord(EnteredDrive[1])-65;    { Get num value of drive. }
  367.  
  368.             Regs.AH := $19;                      { Save current drive. }
  369.             Intr($21,Regs);
  370.  
  371.             OldDrive := Regs.AL;
  372.                                                  { Set current drive for }
  373.             Regs.AH := $E;                       { function $1F. }
  374.             Regs.DL := Drive;
  375.             Intr($21,Regs);
  376.  
  377.             Regs.AH := $1F;         { Undocumented Get Disk Info function. }
  378.             Intr($21,Regs);
  379.  
  380.             if Regs.AL <> 0 then
  381.               begin
  382.                 IndicateError('Error reading disk',ErrInst1,
  383.                               RetryOrCancel,Keystroke);
  384.  
  385.                 if Keystroke = Esc then
  386.                   Signal := True
  387.                 else
  388.                   Window(1,1,80,25);
  389.               end;
  390.           until (Regs.AL = 0) or (Signal);
  391.  
  392.           if not Signal then
  393.             begin
  394.               SectorSize := MemW[Regs.DS:Regs.BX+2];
  395.  
  396.               if MaxAvail < SectorSize+((SectorSize div 16)*SizeOf(ParaRecord)) then
  397.                 begin
  398.                   MemError;
  399.                   Signal := True;
  400.                 end
  401.               else
  402.                 begin
  403.                   ReservedSectors := MemW[Regs.DS:Regs.BX+$B];
  404.  
  405.                   NumSectors := ReservedSectors+
  406.                                 ((MemW[Regs.DS:Regs.BX+$D]-1)*
  407.                                 (longint(Mem[Regs.DS:Regs.BX+4]+1)));
  408.  
  409.                   GetMem(BootPtr,SectorSize);
  410.                   AbsRead(Drive,0,1,BootPtr,Result);
  411.                   FreeMem(BootPtr,SectorSize);
  412.  
  413.                   LargePartition := (Result = $FFFF);
  414.                 end;
  415.             end;
  416.  
  417.           Regs.AH := $E;                   { Restore current drive. }
  418.           Regs.DL := OldDrive;
  419.           Intr($21,Regs);
  420.         end;
  421.     end;
  422. end;
  423.  
  424.  
  425. {---------------------------------------------------------------------------
  426.  AdvancePointer: Advances a pointer value by one byte.  Keeps the segment
  427.  and offset values normalized (offset is always 0..15).
  428.  ---------------------------------------------------------------------------}
  429.  
  430. procedure AdvancePointer(var PtrVar: pointer);
  431. begin
  432.   if PtrRecord(PtrVar).Offset = $0F then
  433.     begin
  434.       PtrRecord(PtrVar).Offset := 0;
  435.       Inc(PtrRecord(PtrVar).Segment);
  436.     end
  437.   else
  438.     Inc(PtrRecord(PtrVar).Offset);
  439. end;
  440.  
  441.  
  442. {---------------------------------------------------------------------------
  443.  Operate: The procedure which allows scrolling of sectors, reading
  444.  sectors, editing sectors, and writing sectors.
  445.  ---------------------------------------------------------------------------}
  446.  
  447. procedure DiskObjType.Operate;
  448. type
  449.   SectorNumStrType = string[10];
  450.  
  451. const
  452.   ASCMinOffset = 59;
  453.   ASCMaxOffset = 74;
  454.  
  455.   DiscardWarning = 'Warning: changes have not been saved';
  456.   DiscardInstruc = 'Press D to discard or Esc to resume editing';
  457.  
  458.   CancelKey = 'C';
  459.  
  460.   DiscardKey = 'D';
  461.   DiscardOrReturn = DiscardKey+Esc;
  462.  
  463. var
  464.   ListPtr: DataListType;
  465.   xPos,yPos: byte;
  466.   ParaOffset: word;
  467.   Keystroke: char;
  468.   CurChar: byte;
  469.   ASCIIEdit: boolean;
  470.   xHexPos: byte;
  471.   PosInHex: byte;
  472.   ParaIdx: byte;
  473.   HeapMark: pointer;
  474.   CurSector: longint;
  475.   OldSector: longint;
  476.   MaxSector: longint;
  477.   SectorBuffer: pointer;
  478.   DataChanged: boolean;
  479.   RespKey: char;
  480.   TerminateLoop: boolean;
  481.   SectorNumStr: SectorNumStrType;
  482.   Signal: boolean;
  483.   StrError: integer;
  484.  
  485.  
  486. {---------------------------------------------------------------------------
  487.  ListInSector: Copies the contents of the sector buffer into a linked list
  488.  of paragraphs.
  489.  ---------------------------------------------------------------------------}
  490.  
  491. procedure ListInSector;
  492. var
  493.   Ctr: word;
  494.   ParaIndex: byte;
  495.   ListPtr: DataListType;
  496.   tNode: DataListType;
  497.   BufPtr: pointer;
  498.   NumIncs: word;
  499.  
  500. begin
  501.   BufPtr := SectorBuffer;
  502.  
  503.   NumIncs := SectorSize div 16;
  504.  
  505.   for Ctr := 1 to NumIncs do
  506.     begin
  507.       New(tNode);
  508.  
  509.       if List = nil then
  510.         begin
  511.           List := tNode;
  512.           tNode^.Prev := nil;
  513.         end
  514.       else
  515.         begin
  516.           tNode^.Prev := ListPtr;
  517.           ListPtr^.Next := tNode;
  518.         end;
  519.  
  520.       ListPtr := tNode;
  521.  
  522.       for ParaIndex := 0 to 15 do
  523.         begin
  524.           ListPtr^.Paragraph[ParaIndex] := Byte(BufPtr^);
  525.           AdvancePointer(BufPtr);
  526.         end;
  527.       end;
  528.  
  529.     ListPtr^.Next := nil;
  530. end;
  531.  
  532.  
  533. {---------------------------------------------------------------------------
  534.  ShowOneLine: Displays the offset, the hex values of the paragraph, and the
  535.  ASCII representation of the paragraph.
  536.  ---------------------------------------------------------------------------}
  537.  
  538. procedure ShowOneLine(ParaPtr: DataListType;Offset: word);
  539. var
  540.   Ctr: byte;
  541.   AccString: string[52];
  542.  
  543. begin
  544.   AccString := '  ';
  545.  
  546.   for Ctr := 0 to 15 do
  547.     AccString := AccString+' '+ToHex(ParaPtr^.Paragraph[Ctr]);
  548.  
  549.   GotoXY(1,WhereY);Write(ToHex(Hi(Offset)),
  550.                          ToHex(Lo(Offset)),AccString);
  551.  
  552.   for Ctr := 0 to 15 do
  553.     PutChar(ASCMinOffset+Ctr,WhereY,ParaPtr^.Paragraph[Ctr]);
  554. end;
  555.  
  556.  
  557. {---------------------------------------------------------------------------
  558.  Show16Lines: Displays the first paragraphs of the sector.
  559.  ---------------------------------------------------------------------------}
  560.  
  561. procedure Show16Lines;
  562. var
  563.   Ctr: byte;
  564.   ListPtr: DataListType;
  565.   LastLineNum: byte;
  566.  
  567. begin
  568.   ListPtr := List;
  569.  
  570.   LastLineNum := SectorSize div 16;
  571.  
  572.   if LastLineNum > 16 then
  573.     LastLineNum := 16;
  574.  
  575.   for Ctr := 0 to LastLineNum-1 do
  576.     begin
  577.       GotoXY(1,Ctr+1);ShowOneLine(ListPtr,Ctr*16);
  578.       ListPtr := ListPtr^.Next;
  579.     end;
  580. end;
  581.  
  582.  
  583. {---------------------------------------------------------------------------
  584.  Cursor. . .: Move the cursor on the specified direction.  Include
  585.  provisions for wrapping and scrolling.
  586.  ---------------------------------------------------------------------------}
  587.  
  588. procedure CursorUp;
  589. begin
  590.   PosInHex := 1;
  591.  
  592.   if ListPtr^.Prev <> nil then
  593.     begin
  594.       Dec(ParaOffset,16);
  595.  
  596.       if yPos <> 1 then
  597.         Dec(yPos)
  598.       else
  599.         begin
  600.           InsLine;
  601.           ShowOneLine(ListPtr^.Prev,ParaOffset);
  602.         end;
  603.     end;
  604.  
  605.   if ListPtr^.Prev <> nil then
  606.     ListPtr := ListPtr^.Prev;
  607. end;
  608.  
  609. procedure CursorDown;
  610. begin
  611.   PosInHex := 1;
  612.  
  613.   if ListPtr^.Next <> nil then
  614.     begin
  615.       Inc(ParaOffset,16);
  616.  
  617.       if (yPos <> 16) then
  618.         Inc(yPos)
  619.       else
  620.         if ListPtr^.Next <>  nil then
  621.           begin
  622.             GotoXY(1,1);DelLine;
  623.             GotoXY(1,16);ShowOneLine(ListPtr^.Next,ParaOffset);
  624.           end;
  625.     end;
  626.  
  627.     if ListPtr^.Next <> nil then
  628.       ListPtr := ListPtr^.Next;
  629. end;
  630.  
  631. procedure CursorLeft;
  632. begin
  633.   PosInHex := 1;
  634.   if xPos > ASCMinOffset then
  635.     Dec(xPos)
  636.   else
  637.     begin
  638.       xPos := ASCMaxOffset;
  639.       CursorUp;
  640.     end;
  641. end;
  642.  
  643. procedure CursorRight;
  644. begin
  645.   PosInHex := 1;
  646.  
  647.   if xPos < ASCMaxOffset then
  648.     Inc(xPos)
  649.   else
  650.     begin
  651.       xPos := ASCMinOffset;
  652.       CursorDown;
  653.     end;
  654. end;
  655.  
  656.  
  657. {---------------------------------------------------------------------------
  658.  IndicateChar: Displays the specified character at the current location in
  659.  the current attribute.
  660.  ---------------------------------------------------------------------------}
  661.  
  662. procedure IndicateChar(Ch: byte);
  663. begin
  664.   SetCursor($FFFF);
  665.   GotoXY(xPos,yPos);PutChar(xPos,yPos,Ch);
  666.   GotoXY(xHexPos,yPos);Write(ToHex(Ch));
  667. end;
  668.  
  669.  
  670. {---------------------------------------------------------------------------
  671.  IndicateChange: Indicates on the screen whether any bytes have been
  672.  changed.
  673.  ---------------------------------------------------------------------------}
  674.  
  675. procedure IndicateChange;
  676. begin
  677.   Window(61,23,80,23);
  678.   TextAttr := BoxAttr;
  679.  
  680.   if DataChanged then
  681.     Write(' Changes unsaved ')
  682.   else
  683.     Write(StringOf(#205,17));
  684.  
  685.   Window(4,5,78,20);
  686. end;
  687.  
  688.  
  689. {---------------------------------------------------------------------------
  690.  DumpSector: Copies the sector data to the list, and displays the first
  691.  16 paragraphs.
  692.  ---------------------------------------------------------------------------}
  693.  
  694. procedure DumpSector;
  695. begin
  696.   Release(HeapMark);
  697.   List := nil;
  698.   ListInSector;
  699.  
  700.   TextAttr := TextNormAttr;Window(4,5,78,20);
  701.   Show16Lines;
  702.   ParaOffset := 0;
  703.   xPos := ASCMinOffset;yPos := 1;
  704.   ListPtr := List;
  705. end;
  706.  
  707.  
  708. {---------------------------------------------------------------------------
  709.  ReadInSector: Reads in the sector into a buffer, and accepts sets up the
  710.  list, and shows the first 16 paragraphs on the screen.
  711.  ---------------------------------------------------------------------------}
  712.  
  713. procedure ReadInSector(var Keystroke: char);
  714. var
  715.   Result: word;
  716.   Signal: boolean;
  717.   WarningKey: char;
  718.   ErrorCode: boolean;
  719.  
  720. begin
  721.   if DataChanged then
  722.     begin
  723.       IndicateError(DiscardWarning,
  724.                     DiscardInstruc,
  725.                     DiscardOrReturn,WarningKey);
  726.       Window(4,5,78,20);
  727.  
  728.       if WarningKey = DiscardKey then
  729.         begin
  730.           DataChanged := False;
  731.           IndicateChange;
  732.           Signal := True;
  733.         end
  734.       else
  735.         begin
  736.           Signal := False;
  737.           Keystroke := CancelKey;
  738.         end;
  739.     end
  740.   else
  741.     Signal := True;
  742.  
  743.   if Signal then
  744.     begin
  745.       repeat
  746.         if LargePartition then
  747.           AugAbsRead(Drive,CurSector,1,SectorBuffer,Result)
  748.         else
  749.           AbsRead(Drive,CurSector,1,SectorBuffer,Result);
  750.  
  751.         Signal := ((Result and $100) <> 0);
  752.  
  753.         if Signal then
  754.           begin
  755.             IndicateError('Error reading disk sector',
  756.                           'Press R to retry, C to cancel, or Esc to end edit',
  757.                           'RC'+Esc,Keystroke);
  758.  
  759.             if Keystroke = CancelKey then
  760.               Window(4,5,78,20);
  761.           end;
  762.       until (not Signal) or (Keystroke = Esc) or (Keystroke = CancelKey);
  763.  
  764.       if (not Signal) then
  765.         begin
  766.           TextAttr := TextHighAttr;
  767.           Window(33,22,80,22);
  768.           Write(CurSector:10);
  769.  
  770.           DumpSector;
  771.           Keystroke := #0;
  772.         end;
  773.     end;
  774. end;
  775.  
  776.  
  777. {---------------------------------------------------------------------------
  778.  WriteSector: Writes the current sector to disk.
  779.  ---------------------------------------------------------------------------}
  780.  
  781. procedure WriteSector;
  782. var
  783.   ListPtr: DataListType;
  784.   BufPtr: pointer;
  785.   Ctr: byte;
  786.   Result: word;
  787.   Keystroke: char;
  788.   ErrMsg: ErrStrType;
  789.   IsError: boolean;
  790.  
  791. begin
  792.   if DataChanged then
  793.     begin
  794.       ListPtr := List;
  795.       BufPtr := SectorBuffer;
  796.  
  797.       while ListPtr <> nil do
  798.         begin
  799.           for Ctr := 0 to 15 do
  800.             begin
  801.               byte(BufPtr^) := ListPtr^.Paragraph[Ctr];
  802.               AdvancePointer(BufPtr);
  803.             end;
  804.  
  805.           ListPtr := ListPtr^.Next;
  806.         end;
  807.  
  808.       IsError := False;
  809.  
  810.       repeat
  811.         if LargePartition then
  812.           AugAbsWrite(Drive,CurSector,1,SectorBuffer,Result)
  813.         else
  814.           AbsWrite(Drive,CurSector,1,SectorBuffer,Result);
  815.  
  816.         if ((Result and $100) <> 0) then
  817.           begin
  818.             IsError := True;
  819.  
  820.             if Lo(Result) = 0 then
  821.               ErrMsg := 'Error: disk is write-protected'
  822.             else
  823.               ErrMsg := 'Error writing disk sector';
  824.  
  825.             IndicateError(ErrMsg,ErrInst1,RetryOrCancel,Keystroke);
  826.             Window(4,5,78,20);
  827.           end
  828.         else
  829.           begin
  830.             IsError := False;
  831.             DataChanged := False;
  832.             IndicateChange;
  833.           end;
  834.       until (not IsError) or (Keystroke = Esc);
  835.     end;
  836. end;
  837.  
  838. begin
  839.   List := nil;
  840.  
  841.   TextAttr := TextHighAttr;
  842.   GotoXY(11,25);Write('F2');
  843.   GotoXY(32,25);Write('F3');
  844.   GotoXY(44,25);Write('F4');
  845.   GotoXY(55,25);Write('F5');
  846.  
  847.   TextAttr := TextNormAttr;
  848.   GotoXY(13,25);Write('-change edit mode');
  849.   GotoXY(34,25);Write('-discard');
  850.   GotoXY(46,25);Write('-update');
  851.   GotoXY(57,25);Write('-new sector');
  852.  
  853.   GetMem(SectorBuffer,SectorSize);
  854.  
  855.   Mark(HeapMark);
  856.  
  857.   ASCIIEdit := False;
  858.  
  859.   PosInHex := 1;
  860.  
  861.   MaxSector := NumSectors-1;
  862.  
  863.   CurSector := 0;
  864.  
  865.   TextAttr := BoxAttr;
  866.   DrawBox(2,3,79,23,DoubleLine);
  867.   GotoXY(3,3);Write(' Offset ');
  868.   GotoXY(13,3);Write(' Hex Dump ');
  869.   GotoXY(62,3);Write(' ASCII Dump ');
  870.  
  871.   TextAttr := TextNormAttr;
  872.   GotoXY(4,22);Write('Drive:');
  873.   GotoXY(25,22);Write('Sector: ');
  874.  
  875.   TextAttr := TextHighAttr;
  876.   GotoXY(11,22);
  877.   if BtoA then
  878.     Write('B')
  879.   else
  880.     Write(Chr(Drive+65));
  881.  
  882.   DataChanged := False;
  883.  
  884.   repeat
  885.     ReadInSector(RespKey);
  886.  
  887.     if RespKey = CancelKey then
  888.       Inc(CurSector);
  889.   until (RespKey = #0) or (RespKey = Esc);
  890.  
  891.   if RespKey <> Esc then
  892.     begin
  893.       TerminateLoop := False;
  894.  
  895.       repeat
  896.         ParaIdx := xPos-ASCMinOffset;
  897.         CurChar := ListPtr^.Paragraph[ParaIdx];
  898.         xHexPos := (xPos-ASCMinOffset-1)*3+11;
  899.  
  900.         TextAttr := $0F;
  901.         IndicateChar(CurChar);
  902.  
  903.         SetCursor($000F);
  904.  
  905.         if ASCIIEdit then
  906.           GotoXY(xPos,yPos)
  907.         else
  908.           GotoXY(xHexPos+PosInHex-1,yPos);
  909.  
  910.         Keystroke := ReadKey;
  911.  
  912.         TextAttr := TextNormAttr;
  913.         IndicateChar(CurChar);
  914.  
  915.         case Keystroke of
  916.           #0: case ReadKey of
  917.                 F1: begin
  918.                       ShowHelpScreen(2);
  919.                       Window(4,5,78,20);
  920.                     end;
  921.                 UpKey: CursorUp;
  922.                 DownKey: CursorDown;
  923.                 LeftKey: if (not ASCIIEdit) and (PosInHex = 2) then
  924.                            PosInHex := 1
  925.                          else
  926.                            CursorLeft;
  927.                 RightKey: CursorRight;
  928.                 #60: ASCIIEdit := not ASCIIEdit;
  929.                 #61: begin
  930.                       if DataChanged then
  931.                         begin
  932.                           DumpSector;
  933.                           DataChanged := False;
  934.                           IndicateChange;
  935.                         end;
  936.                     end;
  937.                 EndKey: begin
  938.                           OldSector := CurSector;
  939.                           CurSector := MaxSector;
  940.                           ReadInSector(RespKey);
  941.  
  942.                           if RespKey = CancelKey then
  943.                             CurSector := OldSector
  944.                           else if RespKey = Esc then
  945.                             TerminateLoop := True;
  946.                         end;
  947.                 HomeKey: begin
  948.                            OldSector := CurSector;
  949.                            CurSector := 0;
  950.                            ReadInSector(RespKey);
  951.  
  952.                            if RespKey = CancelKey then
  953.                              CurSector := OldSector
  954.                            else if RespKey = Esc then
  955.                              TerminateLoop := True;
  956.                          end;
  957.                 PgUpKey: begin
  958.                            if CurSector <> 0 then
  959.                              begin
  960.                                Dec(CurSector);
  961.                                ReadInSector(RespKey);
  962.  
  963.                                if RespKey = CancelKey then
  964.                                  Inc(CurSector)
  965.                                else if RespKey = Esc then
  966.                                  TerminateLoop := True;
  967.                              end;
  968.                            end;
  969.                 PgDnKey: begin
  970.                            if CurSector <> MaxSector then
  971.                              begin
  972.                                Inc(CurSector);
  973.                                ReadInSector(RespKey);
  974.  
  975.                                if RespKey = CancelKey then
  976.                                  Dec(CurSector)
  977.                                else if RespKey = Esc then
  978.                                  TerminateLoop := True;
  979.                              end;
  980.                          end;
  981.                 #62: WriteSector;
  982.                 #63: begin
  983.                        SaveScreen(AuxScreenBuffer);
  984.                        Window(1,1,80,25);
  985.                        TextAttr := TextNormAttr;
  986.                        GotoXY(2,25);ClrEol;
  987.                        Write('Enter a sector number');
  988.  
  989.                        TextAttr := BoxAttr;
  990.                        DrawBox(23,12,57,14,DoubleLine);
  991.  
  992.                        TextAttr := TextNormAttr;
  993.                        GotoXY(25,13);Write('Enter sector number: ');
  994.                        TextAttr := $F;
  995.                        GetInput(SectorNumStr,10,Signal);
  996.                        RestoreScreen(AuxScreenBuffer);
  997.  
  998.                        if not Signal then
  999.                          begin
  1000.                            OldSector := CurSector;
  1001.  
  1002.                            Val(SectorNumStr,CurSector,StrError);
  1003.  
  1004.                            if (CurSector > MaxSector) or (CurSector < 0) or
  1005.                               (StrError <> 0) then
  1006.                              begin
  1007.                                SaveScreen(AuxScreenBuffer);
  1008.  
  1009.                                ErrBox('Error: invalid sector number entered',
  1010.                                       ContMsg,Instruct);
  1011.  
  1012.                                WaitForKeypress;
  1013.                                RestoreScreen(AuxScreenBuffer);
  1014.                                Window(4,5,78,20);
  1015.                                CurSector := OldSector;
  1016.                              end
  1017.                            else
  1018.                              begin
  1019.                                ReadInSector(RespKey);
  1020.  
  1021.                                if RespKey = CancelKey then
  1022.                                  CurSector := OldSector
  1023.                                else if RespKey = Esc then
  1024.                                  TerminateLoop := True;
  1025.                              end;
  1026.                          end
  1027.                        else
  1028.                          Window(4,5,78,20);
  1029.                      end;
  1030.               end;
  1031.             Esc: if DataChanged then
  1032.                    begin
  1033.                      IndicateError(DiscardWarning,
  1034.                                    DiscardInstruc,
  1035.                                    DiscardOrReturn,RespKey);
  1036.  
  1037.                      if RespKey = DiscardKey then
  1038.                        TerminateLoop := True
  1039.                      else
  1040.                        Window(4,5,78,20);
  1041.                    end
  1042.                  else
  1043.                    TerminateLoop := True;
  1044.           else
  1045.             begin
  1046.               if ASCIIEdit then
  1047.                 begin
  1048.                   ListPtr^.Paragraph[ParaIdx] := Ord(Keystroke);
  1049.                   IndicateChar(Ord(Keystroke));
  1050.                   CursorRight;
  1051.  
  1052.                   if not DataChanged then
  1053.                     begin
  1054.                       DataChanged := True;
  1055.                       IndicateChange;
  1056.                     end;
  1057.                 end
  1058.               else
  1059.                 begin
  1060.                   Keystroke := UpCase(Keystroke);
  1061.  
  1062.                   case Keystroke of
  1063.                     '0'..'9',
  1064.                     'A'..'F': begin
  1065.                                 if PosInHex = 1 then
  1066.                                   begin
  1067.                                     PosInHex := 2;
  1068.                                     ListPtr^.Paragraph[ParaIdx] := (ListPtr^.Paragraph[ParaIdx] and $0F)+
  1069.                                                                     FromHex(Keystroke)*16;
  1070.                                    end
  1071.                                  else
  1072.                                    begin
  1073.                                      ListPtr^.Paragraph[ParaIdx] := (ListPtr^.Paragraph[ParaIdx] and $F0)+
  1074.                                                                      FromHex(Keystroke);
  1075.                                      IndicateChar(ListPtr^.Paragraph[ParaIdx]);
  1076.  
  1077.                                      CursorRight;
  1078.                                    end;
  1079.  
  1080.                                 if not DataChanged then
  1081.                                   begin
  1082.                                     DataChanged := True;
  1083.                                     IndicateChange;
  1084.                                   end;
  1085.                               end;
  1086.                     #8: PosInHex := 1;
  1087.                   end;
  1088.                 end;
  1089.             end;
  1090.         end;
  1091.  
  1092.         MemW[$40:$1A] := MemW[$40:$1C];         { Clear keyboard buffer }
  1093.       until TerminateLoop;
  1094.     end;
  1095.   RestoreScreen(BackScreenBuff);
  1096. end;
  1097.  
  1098.  
  1099. {---------------------------------------------------------------------------
  1100.  ProgInterface: the program interface procedure, sets up the screen and
  1101.  calls the menu procedure.
  1102.  ---------------------------------------------------------------------------}
  1103.  
  1104. procedure ProgInterface;
  1105. var
  1106.   BarPos: byte;
  1107.   TerminateLoop: boolean;
  1108.   Signal: boolean;
  1109.  
  1110. {--------------------------------------------------------------------------
  1111.  IntroScreen: Draws the introductory box.  This box disappears when a key
  1112.  other than F1 is pressed.  F1 brings up a screen showing information on
  1113.  the built-in help system.
  1114.  --------------------------------------------------------------------------}
  1115.  
  1116. procedure IntroScreen;
  1117. var
  1118.   Keystroke      : char;
  1119.   TerminateLoop  : boolean;
  1120.   Postn          : byte;
  1121.  
  1122. begin
  1123.   DrawDesktop;
  1124.   GotoXY(2,1);TextAttr := TextNormAttr;Write('DISKEDIT Version 3.00');
  1125.   SaveScreen(BackScreenBuff);
  1126.  
  1127.   DrawIntroBox;
  1128.  
  1129.   TextAttr := TextNormAttr;
  1130.   Writeln('DISKEDIT');
  1131.   Writeln('Disk View/Edit Utility Version 3.00');
  1132.   Writeln('(C)Copyright Gerard Paul Java 1996');
  1133.   Writeln;
  1134.   TextAttr := TextHighAttr;
  1135.   Write('Press F1 for help on help, any other key to continue');
  1136.  
  1137.   TerminateLoop := FALSE;
  1138.  
  1139.   repeat
  1140.     Keystroke := UpCase(ReadKey);
  1141.     case Keystroke of
  1142.       ExtKey: if ReadKey = F1 then
  1143.                 begin
  1144.                   ShowHelpScreen(0);
  1145.                 end
  1146.               else
  1147.                 TerminateLoop := TRUE;
  1148.     else
  1149.       TerminateLoop := TRUE;
  1150.     end;
  1151.   until TerminateLoop;
  1152.  
  1153.   Window(1,1,80,25);
  1154.   RestoreScreen(BackScreenBuff);
  1155.   GotoXY(2,25);Write('F1');
  1156.   TextAttr := TextNormAttr;Write('-help');
  1157.   SaveScreen(BackScreenBuff);
  1158. end;
  1159.  
  1160. begin
  1161.   IntroScreen;
  1162.  
  1163.   Menu.Init;
  1164.  
  1165.   with Menu do
  1166.     begin
  1167.       AddItem('^View/edit disk sectors','Allows viewing and editing of sectors');
  1168.       AddItem('E^xit program','Exits program');
  1169.     end;
  1170.  
  1171.   Menu.SetScreenPos(25,10);
  1172.   Menu.Show;
  1173.   SaveScreen(MenuScreenBuff);
  1174.  
  1175.   BarPos := 1;
  1176.   TerminateLoop := False;
  1177.  
  1178.   repeat
  1179.     Menu.Operate(BarPos,Signal);
  1180.  
  1181.     if Signal then
  1182.       ShowHelpScreen(1)
  1183.     else
  1184.       if BarPos = 1 then
  1185.         begin
  1186.           RestoreScreen(BackScreenBuff);
  1187.           SectorList.SetDrive(Signal);
  1188.           if not Signal then
  1189.             SectorList.Operate;
  1190.  
  1191.           RestoreScreen(MenuScreenBuff);
  1192.         end
  1193.       else
  1194.         TerminateLoop := True;
  1195.   until TerminateLoop;
  1196. end;
  1197.  
  1198. begin
  1199.   Parameter1 := ParamStr(1);
  1200.  
  1201.   if Parameter1 = '/?' then
  1202.     CommandHelp
  1203.   else
  1204.     begin
  1205.       CheckBreak := BreakOff;
  1206.  
  1207.       ScreenInit;
  1208.  
  1209.       if GetEnv('CGASNOWCHECK') = '1' then
  1210.         CheckSnow := SnowCheckOn
  1211.       else
  1212.         CheckSnow := SnowCheckOff;
  1213.  
  1214.       InitValues;
  1215.  
  1216.       ProgInterface;
  1217.  
  1218.       Release(HeapOrg);
  1219.  
  1220.       TerminateProg(0);
  1221.     end;
  1222. end.
  1223.